﻿using Sgr.Caching.Services;
using Sgr.Utilities;

namespace Sgr.Security.VerifyCode
{
    /// <summary>
    /// 默认验证码服务实现
    /// </summary>
    public class DefaultVerifyCodeService : IVerifyCodeService
    {
        private readonly ICacheManager _cacheManager;
        private const string CacheKeyPrefix = "VerifyCode:";

        private const int MaxFailAttempts = 5;         // 最大失败尝试次数

        /// <summary>
        /// 验证码信息类，用于缓存存储
        /// </summary>
        private class VerificationInfo
        {
            public string Code { get; set; } = string.Empty;         // 验证码
            public DateTime AbsoluteTime { get; set; }              // 创建时间
            public int FailedAttempts { get; set; }                 //  失败尝试次数
            public string? LastAttemptCode { get; set; }            //  上次尝试的验证码
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="cacheManager">缓存管理器</param>
        public DefaultVerifyCodeService(ICacheManager cacheManager)
        {
            _cacheManager = cacheManager;
        }

        /// <summary>
        /// 创建验证码
        /// </summary>
        /// <param name="receiverType">接收方式：Phone/Email</param>
        /// <param name="receiver">接收地址（手机号/邮箱）</param>
        /// <param name="purpose">用途</param>
        /// <param name="expireMinutes">过期时间（分钟）</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>验证码创建结果</returns>
        public async Task<string> CreateAsync(
            ReceiverType receiverType,
            string receiver,
            string purpose,
            int expireMinutes = 5,
            CancellationToken cancellationToken = default)
        {
            string code = RandomHelper.GetRandom(100000, 999999).ToString();

            // 生成缓存键
            string cacheKey = GenerateCacheKey(receiverType, receiver, purpose);

            // 创建缓存选项
            DateTime absoluteTime = DateTime.UtcNow.AddSeconds(expireMinutes * 60);// + TimeSpan.FromSeconds(expireMinutes * 60);
            var options = _cacheManager.CreateCacheEntryOptions()
                .SetAbsoluteExpiration(absoluteTime);

            // 创建缓存对象
            var verificationInfo = new VerificationInfo
            {
                Code = code,
                AbsoluteTime = absoluteTime,
                FailedAttempts = 0
            };

            // 将验证码存入缓存
            await _cacheManager.SetAsync(cacheKey, verificationInfo, options, cancellationToken);

            return code;
        }

        /// <summary>
        /// 验证验证码
        /// </summary>
        /// <param name="receiverType">接收方式：Phone/Email</param>
        /// <param name="receiver">接收地址（手机号/邮箱）</param>
        /// <param name="purpose">用途</param>
        /// <param name="code">验证码</param>
        /// <param name="isTemporary">是否临时性的。如果是则不会立即清理验证码缓存状态；如果否则立即清理</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>验证结果</returns>
        public async Task<bool> VerifyAsync(
            ReceiverType receiverType,
            string receiver,
            string purpose,
            string code,
            bool isTemporary = false,
            CancellationToken cancellationToken = default)
        {
            // 生成缓存键
            string cacheKey = GenerateCacheKey(receiverType, receiver, purpose);

            // 获取缓存中的验证码
            var (success, info) = await _cacheManager.TryGetValueAsync<VerificationInfo>(cacheKey, cancellationToken);

            // 如果缓存不存在，或者验证码已过期，则返回失败
            if (!success || info == null)
            {
                return false;
            }

            // 验证码是否过期
            if (info.AbsoluteTime < DateTime.UtcNow)
            {
                await _cacheManager.RemoveAsync(cacheKey, cancellationToken);
                return false;
            }

            // 是否超过最大尝试次数
            if (info.FailedAttempts >= MaxFailAttempts)
            {
                // 可以添加锁定时间机制
                return false;
            }

            // 检查是否为重复提交相同的验证码
            if (code == info.LastAttemptCode)
            {
                return false;
            }

            // 验证码匹配检查（不区分大小写）
            bool isValid = code.Equals(info.Code, StringComparison.OrdinalIgnoreCase);

            if (!isValid)
            {
                info.FailedAttempts++;
                info.LastAttemptCode = code;

                var options = _cacheManager
                    .CreateCacheEntryOptions()
                    .SetAbsoluteExpiration(info.AbsoluteTime);

                await _cacheManager.SetAsync(cacheKey, info, options, cancellationToken);

                return false;
            }

            if (!isTemporary)
            {
                await _cacheManager.RemoveAsync(cacheKey, cancellationToken);
            }

            return true;
        }

        /// <summary>
        /// 生成缓存键
        /// </summary>
        /// <param name="receiverType">接收方式</param>
        /// <param name="receiver">接收地址</param>
        /// <param name="purpose">用途</param>
        /// <returns>缓存键</returns>
        private static string GenerateCacheKey(ReceiverType receiverType, string receiver, string purpose)
        {
            return $"{CacheKeyPrefix}{(int)receiverType}:{purpose}:{receiver}";
        }
    }
}